//
//  ViewController.swift
//  AlamofireUsageDemo1
//
//  Created by 李煜 on 2024/5/8.
//
// 网址
// https://gitcode.gitcode.host/docs-cn/alamofire-docs-cn/Usage.html
//https://www.jianshu.com/p/4381fe8e10b6
import Alamofire
import UIKit

class ViewController: UIViewController {
    @IBOutlet var imageView: UIImageView!

    let baseUrl: String = "https://httpbin.org/get"
    override func viewDidLoad() {
        super.viewDidLoad()

//        requestParameterEncoderDemo3()
//        sixResponseHandlers()
//        download()
        downloadProgress()
    }

    func api() {
//        推荐
//        AF.request(<#T##convertible: any URLConvertible##any URLConvertible#>, method: <#T##HTTPMethod#>, parameters: <#T##Encodable?#>, encoder: <#T##any ParameterEncoder#>, headers: <#T##HTTPHeaders?#>, interceptor: <#T##(any RequestInterceptor)?#>, requestModifier: <#T##Session.RequestModifier?##Session.RequestModifier?##(inout URLRequest) throws -> Void#>)

//        不推荐
//        AF.request(<#T##convertible: any URLConvertible##any URLConvertible#>, method: <#T##HTTPMethod#>, parameters: <#T##Parameters?#>, encoding: <#T##any ParameterEncoding#>, headers: <#T##HTTPHeaders?#>, interceptor: <#T##(any RequestInterceptor)?#>, requestModifier: <#T##Session.RequestModifier?##Session.RequestModifier?##(inout URLRequest) throws -> Void#>)
    }

    // 基础用法
    func basicUsage() {
        AF.request("https://httpbin.org/get").response { response in
            debugPrint(response)
        }
    }

    func api2() {
//        AF.request(<#T##convertible: any URLRequestConvertible##any URLRequestConvertible#>, interceptor: <#T##(any RequestInterceptor)?#>)
    }

    func customHttpMethod() {
        // 自定义httpmethod
        AF.request(baseUrl, method: .custom).response { res in
            debugPrint(res)
        }
    }

    func setupOtherUrlRequestProperty() {
        //        设置其他URLRequest属性:使用requestModifier请求修改器
        AF.request(baseUrl, requestModifier: { $0.timeoutInterval = 5 }).response(completionHandler: { res in
            debugPrint(res)
        })
        AF.request(baseUrl) { $0.timeoutInterval = 5 }.response { res in
            debugPrint(res)
        }
        AF.request(baseUrl) { urlRequest in
            urlRequest.timeoutInterval = 5
            urlRequest.allowsConstrainedNetworkAccess = false
        }.response { res in
            debugPrint(res)
        }
    }

    // MARK: 请求参数和参数编码器

    func requestParameterEncoderDemo1() {
        struct Login: Encodable {
            let email: String
            let password: String
        }

        let login = Login(email: "test@test.test", password: "testpassword")
        AF.request(baseUrl, method: .post, parameters: login, encoder: JSONParameterEncoder.default).response { response in
            debugPrint(response)
        }
    }

    // MARK: 获取具有 URL 编码参数的请求

    func requestParameterEncoderDemo2() {
        let parameters = ["foo": "bar"]

        // 三种形式等价
        let rqt1 = AF.request("https://httpbin.org/get", parameters: parameters) // encoding defaults to `URLEncoding.default`
            .response { res in
                debugPrint(res.request as Any)
            }
        let rqt2 = AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
            .response { res in
                debugPrint(res.request as Any)
            }
        let rqt3 = AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .methodDependent)).response { res in
            debugPrint(res.request as Any)
        }

        // https://httpbin.org/get?foo=bar
    }

    // MARK: 使用 URL 编码的参数发布请求

    func requestParameterEncoderDemo3() {
        let parameters: [String: [String]] = [
            "foo": ["bar"],
            "baz": ["a", "b"],
            "qux": ["x", "y", "z"],
        ]

        // All three of these calls are equivalent
        AF.request("https://httpbin.org/post", method: .post, parameters: parameters).response { res in
            debugPrint("httpbody1: \n \(res.request?.httpBody.debugDescription)")
        }
        AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default).response { res in
            debugPrint(res.request?.httpBody as Any)
        }
        AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .httpBody)).response { res in
            debugPrint(res.request?.httpBody as Any)
        }

        // HTTP body: "qux[]=x&qux[]=y&qux[]=z&baz[]=a&baz[]=b&foo[]=bar"
    }

    // MARK: 配置编码值的排序

    func sortEncoding() {
        // 编码顺序-是否按照字母表顺序
        let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(alphabetizeKeyValuePairs: false))
        // 数组
        let encoder_array = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(arrayEncoding: .brackets))
        // bool
        let encoder_bool = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(boolEncoding: .numeric))
        // data
        let encoder_data = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(dataEncoding: .base64))
        // date
        let encoder_date = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(dateEncoding: .deferredToDate))

//        AF.request("https://httpbin.org/post", encoder:encoder)
    }

    // 键的编码
    func keyEncoding() {
        let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(keyEncoding: .useDefaultKeys))
    }

    // 空格编码
    func blankEncoding() {
        let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(spaceEncoding: .percentEscaped))
    }

    // 使用 JSON 编码参数的 POST 请求
    func jsonEncoding() {
        let parameters: [String: [String]] = [
            "foo": ["bar"],
            "baz": ["a", "b"],
            "qux": ["x", "y", "z"],
        ]

        AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
        AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.prettyPrinted)
        AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.sortedKeys)

        // HTTP body: {"baz":["a","b"],"foo":["bar"],"qux":["x","y","z"]}
    }

    // Configuring a Custom JSONEncoder
    func customJSONEncoder() {
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        encoder.keyEncodingStrategy = .convertToSnakeCase
        let paramterEncoder = JSONParameterEncoder(encoder: encoder)
    }

    // Manual Parameter Encoding of a URLRequest
    func manualEncoderOfURLRequest() {
        let url = URL(string: "https://httpbin.org/get")!
        var urlRequest = URLRequest(url: url)

        let parameters = ["foo": "bar"]
//        let encodedURLRequest = try URLEncodedFormParameterEncoder.default.encode(parameters,into:urlRequest)
        let encodedURLRequest = try? URLEncodedFormParameterEncoder.default.encode(
            parameters,
            into: urlRequest
        )
    }
}

// MARK: http请求头

extension ViewController {
    // 定义一个遵循Decodable协议的结构体
    struct User: Decodable {
        let name: String
        let age: Int

        // 使用CodingKeys枚举来提供键路径
        enum CodingKeys: String, CodingKey {
            case name
            case age
        }
    }

    func headers() {
        // headers创建的两种方式
        let headers1: HTTPHeaders = [
            "Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
            "Accept": "application/json",
        ]
        let headers2: HTTPHeaders = [
            .authorization(username: "Username", password: "password"),
            .accept("application/json"),
        ]

        AF.request("https://httpbin.org/headers", headers: headers1).responseDecodable(of: User.self) { response in
            debugPrint(response)
        }
    }
}

// MARK: 自动验证

extension ViewController {
    func validate() {
        enum Season {
            case spring, summer, autumn, winter
        }
        AF.request(baseUrl).validate(statusCode: 200 ..< 300)
            .validate(contentType: ["application/json"])
            .response { response in
                switch response.result {
                case .success:
                    print("验证成功")
                case let .failure(error):
                    print(error)
                }
            }
    }
}

extension ViewController {
    // MARK: 六个响应handlers

    func sixResponseHandlers() {
        AF.request(baseUrl).response { _ in
        }
//        AF.request(baseUrl).response(responseSerializer: DataResponseSerializerProtocol, completionHandler: <#T##(DataResponse<DataResponseSerializerProtocol.SerializedObject, AFError>) -> Void#>)
//        AF.request(baseUrl).response(responseSerializer: ResponseSerializer, completionHandler: <#T##(DataResponse<ResponseSerializer.SerializedObject, AFError>) -> Void#>)
//        AF.request(baseUrl).responseData(completionHandler: <#T##(AFDataResponse<Data>) -> Void#>)
//        AF.request(baseUrl).responseString(completionHandler: <#T##(AFDataResponse<String>) -> Void#>)
//        AF.request(baseUrl).responseJSON(completionHandler: <#T##(AFDataResponse<Any>) -> Void#>)
//        AF.request(baseUrl).responseDecodable(of: <#T##Decodable.Type#>, queue: <#T##DispatchQueue#>, decoder: <#T##any DataDecoder#>, completionHandler: <#T##(DataResponse<Decodable, AFError>) -> Void#>)
        AF.request("https://httpbin.org/get").response { response in
            debugPrint()
            debugPrint("Response: \(response)")
        }
        AF.request("https://httpbin.org/get").responseData { response in
            debugPrint()

            debugPrint("responseData: \(response)")
        }
        AF.request("https://httpbin.org/get").responseString { response in
            debugPrint()

            debugPrint("responseString: \(response)")
        }
        AF.request("https://httpbin.org/get").responseJSON { response in
            debugPrint()

            debugPrint("responseJSON: \(response)")
        }

        struct HTTPBinResponse: Decodable {
            let url: String
        }

        AF.request("https://httpbin.org/get").responseDecodable(of: HTTPBinResponse.self) { response in
            debugPrint()

            debugPrint("responseDecodable: \(response)")
        }
    }
}

extension ViewController {
    // MARK: 响应处理程序队列

    func responseHandlerQueue() {
        let utilityQueue = DispatchQueue.global(qos: .utility)

        AF.request("https://httpbin.org/get").responseDecodable(of: User.self, queue: utilityQueue) { response in
            print("This closure is executed on utilityQueue.")
            debugPrint(response)
        }
    }
}

extension HTTPMethod {
    static let custom = HTTPMethod(rawValue: "CUSTOM")
}

extension ViewController {
    // MARK: 下载文件
    func downloadReponse1() {
//        AF.download("").response(responseSerializer: DownloadResponseSerializerProtocol) { <#DownloadResponse<DownloadResponseSerializerProtocol.SerializedObject, AFError>#> in
//            
//        }
//        AF.download("").response(responseSerializer: ResponseSerializer, completionHandler: <#T##(DownloadResponse<ResponseSerializer.SerializedObject, AFError>) -> Void#>)
    }
    func download() {
        AF.download("https://httpbin.org/image/png").responseData { response in
            if let data = response.value {
                let image = UIImage(data: data)
                self.imageView.image = image
            }
        }
    }

    // MARK: 下载文件的存放位置

    func downloadPath() {
        // 一.自定义destination
        AF.download("https://httpbin.org/image/png", to: { _, _ in
            let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let fileURL = documentsURL.appendingPathComponent("image.png")
            return (fileURL, [.createIntermediateDirectories, .removePreviousFile])
        }).response { response in
            debugPrint(response)

            if response.error == nil, let imagePath = response.fileURL?.path {
                let image = UIImage(contentsOfFile: imagePath)
            }
        }

        // 二.使用建议的destination
        let des = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
        AF.download("https://httpbin.org/image/png", to: des)
    }
}

// MARK: - 下载进度

extension ViewController {
    func downloadProgress() {
        AF.download("https://httpbin.org/image/png")
            .downloadProgress { progress in
                debugPrint("下载进度: \(progress.fractionCompleted)")
            }
            .responseData { response in
                if let data = response.value {
                    let image = UIImage(data: data)
                }
            }
    }
    func downloadProgressWithQueue() {
        AF.download("")
            .downloadProgress(queue: .global(qos: .utility)) { progress in
                debugPrint("下载进度: \(progress.fractionCompleted)")
            }
            .responseData { response in
                if let data = response.value {
                    let image = UIImage(data: data)
                }
            }
    }
    
    
}
//https://www.yc00.com/news/1701530514a1108900.html?btwaf=11959744
//MARK: 断点下载
class ImageRequestor {
    private var resumeData: Data?
    private var image: UIImage?
    func fetchImage(completion: (UIImage?) -> Void) { 
        guard image == nil else { completion(image); return }
        let destination: DownloadRequest.Destination = { _, _ in
            var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let fileURL = documentsURL.appendingPathComponent("pig.png")
            return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
        }
        let request: DownloadRequest
        if let resumeData = resumeData {
//            request = AF.download(resumingWith: resumeData)
            request = AF.download(resumingWith: resumeData,to: destination)

        } else {
            request = AF.download("")
        }
        request.responseData { response in
            switch response.result {
                case let .success(data):
                    self.image = UIImage(data: data)
                case .failure:
                    self.resumeData = response.resumeData
            }
        }
    }
}

//MARK: 上传
extension ViewController {
    
}

//MARK: 路由
enum Router: URLRequestConvertible {
    case search(query: String, page: Int)
    static let baseURLString = ""
    static let perPage = 50
    // MARK: URLRequestConvertible
    func asURLRequest() throws -> URLRequest {
        let result: (path: String, parameters: Parameters) = {
            switch self {
                case let .search(query, page) where page > 0:
                    return ("/search", ["q": query, "offset": Router.perPage * page])
                case let .search(query, _):
                    return ("/search", ["q": query])
            }
        }()
        let url = try Router.baseURLString.asURL()
        let urlRequest = URLRequest(url: url.appendingPathComponent(result.path))
        return try URLEncoding.default.encode(urlRequest, with: result.parameters)
    }
}

enum XMRouter: URLRequestConvertible {
    func asURLRequest() throws -> URLRequest {
        let result: (path: String, param: Parameters) = {
            switch self {
                case let .search(query, page):
                    let p = ["key": XMRouter.consumerKey]
                    return ("/search",p)
                case let .photoInfo(id, size):
                    let p = ["key": Self.consumerKey]
                    return ("/search",p)
                case let .favorites(catetory, list):
                    return ("/favorites",["list": XMRouter.list])
            }
        }()
        
        let url = try XMRouter.baseURLString.asURL().appendingPathComponent(result.path)
        let request = URLRequest(url: url)
        return try URLEncoding.default.encode(request, with: result.param)
    }
    static let baseURLString = "https://api.host.com/v1"
    static let consumerKey = "消费者密钥"

    case search(query: String, page: Int)
    case photoInfo(Int, Int)
    
}
enum BRouter: URLRequestConvertible {
    case createUser(parameters: Parameters)
    case readUser(username: String)
    case updateUser(username: String, parameters: Parameters)
    case destroyUser(username: String)
    
    static let baseURLString = ""
    
    var method: HTTPMethod {
        switch self {
        case .createUser: return .post
        case .readUser: return .get
        case .updateUser: return .put
        case .destroyUser: return .delete
        }
    }
    var path: String {
        switch self {
        case .createUser: return "/users"
        case let .readUser(username): return "/users/\(username)"
        case let .updateUser(username, _): return "/users/\(username)"
        case let .destroyUser(username): return "/users/\(username)"
        }
    }
    // MARK: URLRequestConvertible
    func asURLRequest() throws -> URLRequest {
        let url = try Self.baseURLString.asURL()
        var urlRequest = URLRequest(url: url.appendingPathComponent(path))
        urlRequest.httpMethod = method.rawValue
        switch self {
        case let .createUser(parameters):
            urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters)
        case let .updateUser(_, parameters):
            urlRequest = try URLEncoding.default.encode(
                urlRequest,
                with: parameters
            )
               
                //URLEncodedFormParameterEncoder.default.encode写法
                // 此处.updateUser(_, parameters):的parameters是[String: Any],需要是 Parameters:Encodable,any不符合Encodable
//            urlRequest = try URLEncodedFormParameterEncoder.default.encode(
//                parameters,
//                into: urlRequest
//            )
        default: break
        }
        return urlRequest
    }
}
extension ViewController {
    //MARK: 使用路由
    func UseRouter() {
        AF.request(BRouter.readUser(username: "Jerry")).response { res in }
    }
}


//MARK: - 6.自定义响应序列者
enum BackendError: Error {
    case network(error: Error) // Capture any underlying Error from the URLSession APIcase dataSerialization(error: Error)
    case jsonSerialization(error: Error)
    case xmlSerialization(error: Error)
    case objectSerialization(reason: String)
}
